package yiyuan.code.filedemo.file.operator;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.csource.common.MyException;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.*;
import sun.reflect.generics.reflectiveObjects.NotImplementedException;
import yiyuan.code.filedemo.file.dto.ObjectResponse;
import yiyuan.code.filedemo.file.dto.UploadRequestParam;
import yiyuan.code.filedemo.file.exception.FileOperatorException;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;

/**
 * FastDfs文件操作器
 *
 */
@Slf4j
public class FastDfsFileOperator extends AbstractFileOperator {

  private TrackerClient trackerClient;
  /**
   * 成功
   */
  private static final int SUCCESS_CODE = 0;
  /**
   * 未找到节点或文件
   */
  private static final int ERROR_CODE_NONE = 2;

  @Override
  public void init(Map<String, String> params) {
    log.info("FastDfs文件服务-初始化开始 | params:[{}]", params);
    String trackerList = params.get("trackerList");
    String soTimeout = params.get("soTimeout");
    String connectTimeout = params.get("connectTimeout");
    if (StringUtils.isAnyBlank(trackerList, soTimeout, connectTimeout)) {
      throw new FileOperatorException("FastDfs文件服务-初始化参数错误");
    }
    try {
      Properties props = new Properties();
      props.put(ClientGlobal.PROP_KEY_TRACKER_SERVERS, trackerList);
      props.put(ClientGlobal.PROP_KEY_NETWORK_TIMEOUT_IN_SECONDS, soTimeout);
      props.put(ClientGlobal.PROP_KEY_CONNECT_TIMEOUT_IN_SECONDS, connectTimeout);
      ClientGlobal.initByProperties(props);
      trackerClient = new TrackerClient();
      //创建一次连接
      this.getStorageClient();
    } catch (Exception e) {
      log.error("FastDfs文件服务-初始化tracker异常", e);
      throw new FileOperatorException("FastDfs文件服务-初始化tracker异常", e);
    }
    log.info("FastDfs文件服务-初始化完成 | {}", ClientGlobal.configInfo());
  }

  @Override
  public ObjectResponse uploadFile(UploadRequestParam requestParam, InputStream inputStream) {
    String[] storePaths;
    try {
      final Map<String, String> metadata = requestParam.getMetadata();
      NameValuePair[] pairs = null;
      if (metadata != null) {
        pairs = (NameValuePair[]) metadata.entrySet().stream()
          .map(entry -> new NameValuePair(entry.getKey(), entry.getValue())).toArray();
      }
      storePaths = this.getStorageClient().upload_file("",
        requestParam.getSize(),
        new UploadStream(inputStream, requestParam.getSize()),
        requestParam.getExtName(),
        pairs);
    } catch (Exception e) {
      log.error("FastDfs文件服务-上传文件异常", e);
      throw new FileOperatorException("FastDfs文件服务-上传文件异常", e);
    }
    return ObjectResponse.builder()
      .key(requestParam.getKey())
      .storePath(storePaths[0] + STORE_SPLIT + storePaths[1])
      .build();
  }

  @Override
  public void getFileAsStream(String storePath, Consumer<InputStream> streamConsumer) {
    String[] paths = storePath.split(STORE_SPLIT, 2);
    try {
      Path tempFile = Files.createTempFile("fastdsf-", ".temp");
      final int code = this.getStorageClient().download_file(paths[0], paths[1], tempFile.toString());
      if (code != SUCCESS_CODE) {
        throw new FileOperatorException("FastDfs文件服务-文件下载失败 | 错误码：" + code);
      }
      streamConsumer.accept(new FileInputStream(tempFile.toFile()));
    } catch (Exception e) {
      log.error("FastDfs文件服务-获取文件下载流异常", e);
      throw new FileOperatorException("FastDfs文件服务-获取文件下载流异常", e);
    }
  }

  @Override
  public ObjectResponse copyFile(String storePath, UploadRequestParam targetParam) {
    String[] paths = storePath.split(STORE_SPLIT, 2);
    String originGroup = paths[0];
    String originPath = paths[1];
    //获取源文件信息
    final FileInfo fileInfo;
    try {
      fileInfo = this.getStorageClient().get_file_info(originGroup, originPath);
    } catch (IOException | MyException e) {
      log.error("FastDfs文件服务-文件复制查询异常", e);
      throw new FileOperatorException("FastDfs文件服务-文件复制查询异常", e);
    }
    UploadRequestParam requestParam = UploadRequestParam.builder()
      .size(fileInfo.getFileSize()).extName(FilenameUtils.getExtension(originPath))
      .build();
    //下载上传
    AtomicReference<ObjectResponse> response = new AtomicReference<>();
    try {
      this.getFileAsStream(storePath, (is) -> response.set(this.uploadFile(requestParam, is)));
    } catch (Exception e) {
      log.error("FastDfs文件服务-文件复制异常", e);
      throw new FileOperatorException("FastDfs文件服务-文件复制异常", e);
    }
    return response.get();
  }

  @Override
  public void deleteFile(String storePath) {
    String[] paths = storePath.split(STORE_SPLIT, 2);
    try {
      final int code = this.getStorageClient().delete_file(paths[0], paths[1]);
      if (code != SUCCESS_CODE && code != ERROR_CODE_NONE) {
        throw new FileOperatorException("FastDfs文件服务-文件删除失败 | 错误码：" + code);
      }
    } catch (Exception e) {
      log.error("FastDfs文件服务-文件删除异常", e);
      throw new FileOperatorException("FastDfs文件服务-文件删除异常", e);
    }
  }

  @Override
  public String getFileDownloadUrl(String storePath, int duration, TimeUnit unit) {
    throw new NotImplementedException();
  }

  private StorageClient getStorageClient() {
    try {
      return new StorageClient(trackerClient.getTrackerServer());
    } catch (IOException e) {
      log.error("FastDfs文件服务-创建服务连接异常", e);
      throw new FileOperatorException("FastDfs文件服务-创建服务连接异常", e);
    }
  }

  @Override
  public void destroy() {
    trackerClient = null;
  }
}
